package argtrust.certprop;

import java.util.LinkedHashMap;
import java.util.Map;

import argtrust.certprop.CertPropMeasure;
import argtrust.certprop.CertPropMeasureOperators;
import argtrust.measure.IMeasureOperators;
import argtrust.measure.Measure;
import argtrust.trustnet.Agent;
import argtrust.trustnet.AgentPair;
import argtrust.trustnet.ITrustSemantics;
import argtrust.trustnet.IndirectTrust;
import argtrust.trustnet.Trust;
import argtrust.trustnet.TrustLink;
import argtrust.trustnet.TrustNet;
import argtrust.trustnet.TrustNode;

public class CertPropTrust implements ITrustSemantics {

    Map<AgentPair, Measure> mTrustTable = new LinkedHashMap<AgentPair, Measure>();
    TrustNet mTrustnet;
    CertPropMeasureOperators mOperators = new CertPropMeasureOperators();

    public CertPropTrust(TrustNet trust_net) {
        mTrustnet = trust_net;
    }

    CertPropMeasure getCertPropMeasure(Measure measure) {
        if (measure.getOpMeasure() instanceof CertPropMeasure) {
            return (CertPropMeasure) measure.getOpMeasure();
        } else {
            //TODO: throw exception
            System.err.println(this.getClass().getName()
                    + " is having trouble in understanding the measure type.");
            if (measure != null) {
                System.err.println("Measure type: " + measure.getClass().getName());
            }
            return null;
        }
    }

    public CertPropMeasure getCertPropMeasure(Agent agent, Agent other) {
        return getCertPropMeasure(trust(agent, other));

    }

    @Override
    public Measure trust(Agent agent, Agent other) {
        AgentPair edge = new AgentPair(agent, other);
        Measure res = mTrustTable.get(edge);
        if (res == null) {
            TrustNode trust_node = mTrustnet.getTrustNode(agent);

            CertPropMeasure trust = new CertPropMeasure();

            for (TrustLink trust_link : trust_node.getTrustLinkList()) {
                Trust tr = trust_link.getTrust();
                if (tr.getTail().equals(other)) {

                    res = new CertPropMeasure(
                            getCertPropMeasure(tr.getMeasure()));
                    mTrustTable.put(edge, res);
                    return res;
                }

                CertPropMeasure concatenated =
                        mOperators.concatenate(
                        getCertPropMeasure(tr.getMeasure()),
                        getCertPropMeasure(tr.getTail(), other));
                trust = mOperators.aggregate(trust, concatenated);
            }
            IndirectTrust ind_trust = new IndirectTrust();
            ind_trust.setMeasure(trust);
            mTrustTable.put(edge, ind_trust);
            res = ind_trust;
        }
        return res;
    }

    @Override
    public IMeasureOperators getOperators() {
        return mOperators;
    }

    public static void main(String[] args) {
        TrustNet trust_net = new TrustNet();
        //Agent:
        Agent one = trust_net.getAgent("1");
        Agent two = trust_net.getAgent("2");
        Agent three = trust_net.getAgent("3");
        Agent four = trust_net.getAgent("4");
        Agent five = trust_net.getAgent("5");
        Agent six = trust_net.getAgent("6");

        trust_net.trust(one, two, new CertPropMeasure(20, 5));
        trust_net.trust(one, three, new CertPropMeasure(0, 5));
        trust_net.trust(one, four, new CertPropMeasure(20, 0));
        trust_net.trust(two, five, new CertPropMeasure(5, 5));
        trust_net.trust(three, five, new CertPropMeasure(15, 5));
        trust_net.trust(three, six, new CertPropMeasure(1, 1));
        trust_net.trust(four, six, new CertPropMeasure(20, 20));
        trust_net.trust(five, six, new CertPropMeasure(20, 0));

        CertPropTrust trust = new CertPropTrust(trust_net);
        System.out.println(trust.trust(one, six));
    }
}
